package com.pipe.protocol;

import com.pipe.util.IntegerConveter;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

/**
 * @author Kiven
 */
public class BasePackage {
    private int payLoadLen;
    private byte sequenceId;
    private ByteBuf payLoadByteBuf;

    public BasePackage(int payLoadLen, byte sequenceId, byte[] payloadArr, ByteBuf byteBuf) {
        this.payLoadLen = payLoadLen;
        this.sequenceId = sequenceId;
        this.payLoadByteBuf = byteBuf;
    }

    public static BasePackage build(int payLoadLen, byte sequenceId, byte[] payLoad, ByteBuf byteBuf){
        return new BasePackage(payLoadLen, sequenceId, payLoad, byteBuf);
    }

    public void resetPayload(ByteBuf payLoadByteBuf){
        this.payLoadLen = payLoadByteBuf.readableBytes();
        this.sequenceId = (byte) (this.sequenceId + 1);
        this.payLoadByteBuf = payLoadByteBuf;
    }

    public void resetPayloadAndSession(ByteBuf payLoadByteBuf){
        resetPayload(payLoadByteBuf);
        this.sequenceId = 0;
    }

    public static BasePackage getBasePackage(ByteBuf msg) {
        if (notEnoughData(msg)){
            return null;
        }
        byte[] payloadLength = new byte[3];
        msg.readBytes(payloadLength, 0, 3);
        int len = IntegerConveter.getIntFromByte3(payloadLength);

        byte[] sequenceId = new byte[1];
        msg.readBytes(sequenceId, 0, 1);

        ByteBuf byteBuf = msg.copy(msg.readerIndex(), len);
        byte[] payLoad = new byte[len];
        msg.readBytes(payLoad, 0, len);

        return BasePackage.build(len, sequenceId[0], payLoad, byteBuf);
    }

    private static boolean notEnoughData(ByteBuf msg){
        byte[] payloadLength = new byte[3];
        msg.getBytes(msg.readerIndex(), payloadLength);

        int len = IntegerConveter.getIntFromByte3(payloadLength);
        if (msg.readableBytes() < (len + 4)){
            return true;
        }
        return false;
    }

    public ByteBuf toBytebuf() {
        byte[] payLoadLenArr = IntegerConveter.getByte3ArrayFromInt(payLoadLen);
        ByteBuf byteBuf = Unpooled.directBuffer(payLoadLenArr.length + 1 + payLoadByteBuf.readableBytes());
        byteBuf.writeBytes(payLoadLenArr);
        byteBuf.writeByte(sequenceId);
        byteBuf.writeBytes(payLoadByteBuf);
        return byteBuf;
    }

    public int getPayLoadLen() {
        return payLoadLen;
    }

    public ByteBuf getPayLoadByteBuf() {
        return payLoadByteBuf;
    }

    public byte getSequenceId() {
        return sequenceId;
    }
}